#include "BindSystem.hpp"

using namespace luabind;
namespace bind
{
	namespace SFML
	{
		namespace system
		{
			/*void Config(lua_State* lua)
			{
			}*/
				
			void BClock(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						class_<sf::Clock>("Clock")
							.def(constructor<>())
							.def("GetElapsedTime", &sf::Clock::GetElapsedTime)
							.def("Reset", &sf::Clock::Reset)
					];
			}

			void BContext(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						class_<sf::Context>("Context")
							.def(constructor<>())
							.def("SetActive", &sf::Context::SetActive)
							.def("SetReferenceActive", &sf::Context::SetReferenceActive)
					];
			}
				
			void BLock(lua_State* lua, const std::string& ns)
			{
			}
				
			void BMutex(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						class_<sf::Lock>("Lock")
							.def(constructor<sf::Mutex&>()),

						class_<sf::Mutex>("Mutex")
							.def(constructor<>())
							.def("Lock", &sf::Mutex::Lock)
							.def("Unlock", &sf::Mutex::Unlock)
					];
			}

			void BNonCopyable(lua_State* lua, const std::string& ns)
			{
			}
				
			void BRandomizer(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						class_<sf::Randomizer>("Randomizer")
							.def("SetSeed", &sf::Randomizer::SetSeed)
							.def("GetSeed", &sf::Randomizer::GetSeed)
							.def("Random", (float(*)(sf::Randomizer&, float, float))&sf::Random<float>)
							.def("Random", (int(*)(sf::Randomizer&, int, int))&sf::Random<int>)
					];
			}
				
			void BSleep(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						def("Sleep", &sf::Sleep)
					];
			}

			void BThread(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						class_<sf::Thread>("Thread")
							.def("Launch", &sf::Thread::Launch)
							.def("Wait", &sf::Thread::Wait)
							.def("Terminate", &sf::Thread::Terminate)
					];
			}
				
			template <class T, typename A>
			void BThread(lua_State* lua, const std::string& ns)
			{
				//typedef void(T::*func)();
				/*
				module(lua, ns.c_str())
					[
						class_<sf::Thread>("Thread")
							.def(constructor<T>())
							.def(constructor<T, A>())
							//.def(constructor<func, T*>())
							.def("Launch", &sf::Thread::Launch)
							.def("Wait", &sf::Thread::Wait)
							.def("Terminate", &sf::Thread::Terminate)
					];*/
			}

			void BThreadLocal(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						class_<sf::ThreadLocal>("ThreadLocal")
							.def(constructor<void*>())
							.def("SetValue", &sf::ThreadLocal::SetValue)
							.def("GetValue", &sf::ThreadLocal::GetValue)
					];
			}

			template <typename T>
			void BThreadLocalPtr(lua_State* lua, const std::string& ns)
			{
				/*module(lua, ns.c_str())
					[
						class_<sf::ThreadLocalPtr<T>, bases<sf::ThreadLocal> >("ThreadLocalPtr")
							.def(constructor<(T*)>)
					];*/
			}
				
			template <unsigned int T, typename In, typename Out>
			void BUtf(lua_State* lua, const std::string& ns)
			{
				std::stringstream ss;
				ss << T;

				module(lua, ns.c_str())
					[
						class_<sf::Utf<T> >(std::string(std::string("Utf") + ss.str()).c_str())
							.def("Decode", &sf::UtfDecode<T, In>)
							.def("Encode", &sf::UtfEncode<T, Out>)
							.def("Next", &sf::UtfNext<T, In>)
							.def("Count", &sf::UtfCount<T, In>)
							.def("FromAnsi", &sf::UtfFromAnsi<T, In, Out>)
							.def("FromWide", &sf::UtfFromWide<T, In, Out>)
							.def("ToAnsi", &sf::UtfToAnsi<T, In, Out>)
							.def("ToWide", &sf::UtfToWide<T, In, Out>)
							.def("ToUtf8", &sf::UtfToUtf8<T, In, Out>)
							.def("ToUtf16", &sf::UtfToUtf16<T, In, Out>)
							.def("ToUtf32", &sf::UtfToUtf32<T, In, Out>)
					];
			}
				
			void BResource(lua_State* lua, const std::string& ns)
			{
			}
				
			template <typename T>
			void BVector2(lua_State* lua, const std::string& ns, const std::string& name)
			{
				module(lua, ns.c_str())
					[
						class_<sf::Vector2<T> >(std::string(std::string("Vector2") + name).c_str())
							.def(constructor<T, T>())
							.def_readwrite("x", &sf::Vector2<T>::x)
							.def_readwrite("y", &sf::Vector2<T>::y)
					];
			}
				
			template <typename T>
			void BVector3(lua_State* lua, const std::string& ns, const std::string& name)
			{
				module(lua, ns.c_str())
					[
						class_<sf::Vector3<T> >(std::string(std::string("Vector3") + name).c_str())
							.def(constructor<T, T, T>())
							.def_readwrite("x", &sf::Vector3<T>::x)
							.def_readwrite("y", &sf::Vector3<T>::y)
							.def_readwrite("z", &sf::Vector3<T>::z)
					];
			}

			void BMatrix3(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						class_<sf::Matrix3>("Matrix3")
							.def(constructor<>())
							.def(constructor<float, float, float, float, float, float, float, float, float>())
							.def("Transform", &sf::Matrix3::Transform)
							.def("GetInverse", &sf::Matrix3::GetInverse)
							.def("Get4x4Elements", &sf::Matrix3::Get4x4Elements)
							.def(const_self * other<const sf::Matrix3&>()),

						def("Transformation", &sf::Transformation),
						def("Projection", &sf::Projection)
					];

					LUA_CONST_START(lua, sf::Matrix3)
					LUA_CONST(sf::Matrix3, Identity)
					LUA_CONST_END
			}
				
			template <typename T>
			void BRect(lua_State* lua, const std::string& ns, const std::string& name)
			{
				module(lua, ns.c_str())
					[
						class_<sf::Rect<T> >(std::string(name + std::string("Rect")).c_str())
							.def(constructor<>())
							.def(constructor<T, T, T, T>())
							.def(constructor<const sf::Vector2<T>&, const sf::Vector2<T>&>())
							.def("Contains", (bool(sf::Rect<T>::*)(T, T)const)&sf::Rect<T>::Contains)
							.def("Contains", (bool(sf::Rect<T>::*)(const sf::Vector2<T>&)const)&sf::Rect<T>::Contains)
							.def("Intersects", (bool(sf::Rect<T>::*)(const sf::Rect<T>&)const)&sf::Rect<T>::Intersects)
							.def("Intersects", (bool(sf::Rect<T>::*)(const sf::Rect<T>&, sf::Rect<T>&)const)&sf::Rect<T>::Intersects)
							.def_readwrite("Left", &sf::Rect<T>::Left)
							.def_readwrite("Top", &sf::Rect<T>::Top)
							.def_readwrite("Width", &sf::Rect<T>::Width)
							.def_readwrite("Height", &sf::Rect<T>::Height)
					];
			}
				
			void BListener(lua_State* lua, const std::string& ns)
			{
			}
				
			void Bind(lua_State* lua, const std::string& ns)
			{
				open(lua);
				//Config(lua, ns);
				BClock(lua, ns);
				BContext(lua, ns);
				BLock(lua, ns);
				BMutex(lua, ns);
				BNonCopyable(lua, ns);
				BRandomizer(lua, ns);
				BSleep(lua, ns);
				BThread(lua, ns);
				BThread<int, int>(lua, ns);
				BThread<float, float>(lua, ns);
				BThread<std::string&, std::string&>(lua, ns);
				BThreadLocal(lua, ns);
				BThreadLocalPtr<int>(lua, ns);
				BThreadLocalPtr<float>(lua, ns);
				BThreadLocalPtr<std::string>(lua, ns);
				/*BUtf<8, char, char>(lua, ns);
				BUtf<16, char, char>(lua, ns);
				BUtf<32, char, char>(lua, ns);*/
				BResource(lua, ns);
				BVector2<int>(lua, ns, std::string("i"));
				BVector2<float>(lua, ns, std::string("f"));
				BVector3<int>(lua, ns, std::string("i"));
				BVector3<float>(lua, ns, std::string("f"));
				BMatrix3(lua, ns);
				BRect<int>(lua, ns, std::string("Int"));
				BRect<float>(lua, ns, std::string("Float"));
				BListener(lua, ns);
			}
		}
	}
}